/**
 * 目前对monkey解析器的性能没有什么要求，因此我们选择了简单的方法，也就是对monkey源代码求值时，每个遇到的值都会用Object表示。
 * 这个Object是为Monkey设计的接口。具体来说，所有的值都被封装到一个符合Object接口的结构体中。
 */
use std::any::Any;
use std::sync::Arc;
type ObjectType = String;
pub const INTEGER_OBJ: &'static str = "INTEGER";
pub const BOOLEAN_OBJ: &'static str = "BOOLEAN";
pub const NULL_OBJ: &'static str = "NULL";
pub const RETURN_VALUE_OBJ: &'static str = "RETURN_VALUE";
pub const ERROR_OBJ: &'static str = "ERROR";
pub trait Object{
    fn get_type(&self) -> ObjectType;
    fn inspect(&self) -> String;
    fn as_any(&self) -> &dyn Any;
}

pub struct Integer{
    pub value: i64,
}

impl Object for Integer{
    fn get_type(&self) -> ObjectType{
        INTEGER_OBJ.to_string()
    }
    fn inspect(&self) -> String{
        // self.value.to_string()
        format!("{}", self.value)
    }
    fn as_any(&self) -> &dyn Any{
        self
    }
}

impl PartialEq for dyn Object {
    fn eq(&self, other: &Self) -> bool {
        // unimplemented!()
        self.inspect() == other.inspect()
    }
}

pub struct Boolean{
    pub value: bool,
}

impl Object for Boolean{
    fn get_type(&self) -> ObjectType{
        BOOLEAN_OBJ.to_string()
    }
    fn inspect(&self) -> String{
        // self.value.to_string()
        format!("{}", self.value)
    }
    fn as_any(&self) -> &dyn Any{
        self
    }
}

//空引用
pub struct Null;
impl Object for Null{
    fn get_type(&self) -> ObjectType{
        NULL_OBJ.to_string()
    }
    fn inspect(&self) -> String{
        "null".to_string()
    }
    fn as_any(&self) -> &dyn Any{
        self
    }
}

/*
前言：
下面是Monkey程序中的顶层return语句:
5 * 5 * 5;
return 10;
9 * 9 * 9;
求值时，该程序应返回10。如果这些语句是函数的主体，则调用该函数得到的值为10。这里的重点在于，永远不会对最后一行9 * 9 * 9表达式求值。
实现return语句的方式有多种。在某些宿主语言中，可以使用goto或异常。因此，为了支持return语句，求值器需要传递一个“返回值”。每当遇到return时，就将应返回的值封装在一个对象中，以便跟踪。我们需要追踪这个对象，这样就可以在稍后决定是否停止求值。
*/
pub struct ReturnValue{
    pub value: Arc<dyn Object>,
}

impl Object for ReturnValue {
    fn get_type(&self) -> ObjectType{
        RETURN_VALUE_OBJ.to_string()
    }
    fn inspect(&self) -> String{
        self.value.inspect()
    }
    fn as_any(&self) -> &dyn Any{
        self
    }
}

// 首先，明确什么是“真正的错误处理”。错误处理并不是指用户自定义的异常，而是指程序内部的错误处理流程。它用于处理错误的运算符、不被支持的操作以及在执行期间可能发生的其他用户错误或内部错误。
// 从实现角度来看，这些错误可能让人觉得奇怪，因为错误处理的实现方式几乎与 return 语句相同。道理很简单：错误处理和 return 语句都会终止对一系列语句的求值。
#[derive(Clone)]
pub struct Error{
    pub message: String,
}

impl Object for Error {
    fn get_type(&self) -> ObjectType{
        ERROR_OBJ.to_string()
    }
    fn inspect(&self) -> String{
        format!("ERROR: {}", self.message) 
    }
    fn as_any(&self) -> &dyn Any{
        self
    }
}

mod environment;